/*
@STI LICENSE
(C) 2006-2008 Universit�t Innsbruck.

This file is part of myOntology.

myOntologyis free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

myOntologyis distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with myOntology.  If not, see <http://www.gnu.org/licenses/>.

@STI LICENSE */
package controller.elementMapper;

import java.util.ArrayList;
import java.util.Iterator;

import model.Vocabulary;

import org.openrdf.model.URI;
import org.openrdf.repository.RepositoryConnection;

import controller.HelperFunctions;
import controller.sesameDataConnector.AbstractDataConnector;


public class ClassMapper extends Mapper {


	protected ArrayList<Exception> exceptionsSubclassOf = null;
	protected ArrayList<Exception> exceptionAllClassesHavingClassInSubClassOf = null;
	protected ArrayList<Exception> exceptionAllPropertiesHavingClassInDomain = null;
	protected ArrayList<Exception> exceptionAllPropertiesHavingClassInRange = null;

	protected void addExceptionSubclassOf( Exception ex ) {
		
		if( this.exceptionsSubclassOf==null )
			this.exceptionsSubclassOf = new ArrayList<Exception>();
		this.exceptionOccured = true;
		this.exceptionsSubclassOf.add( ex );
	}
	public ArrayList<Exception> getExceptionSubclassOf() {
		return this.exceptionsSubclassOf;
	}

	protected void addExceptionAllClassesHavingClassInSubClassOf( Exception ex ) {
		
		if( this.exceptionAllClassesHavingClassInSubClassOf==null )
			this.exceptionAllClassesHavingClassInSubClassOf = new ArrayList<Exception>();
		this.exceptionOccured = true;
		this.exceptionAllClassesHavingClassInSubClassOf.add( ex );
	}
	public ArrayList<Exception> getExceptionAllClassesHavingClassInSubClassOf() {
		return this.exceptionAllClassesHavingClassInSubClassOf;
	}

	protected void addExceptionAllPropertiesHavingClassInDomain( Exception ex ) {
		
		if( this.exceptionAllPropertiesHavingClassInDomain==null )
			this.exceptionAllPropertiesHavingClassInDomain = new ArrayList<Exception>();
		this.exceptionOccured = true;
		this.exceptionAllPropertiesHavingClassInDomain.add( ex );
	}
	public ArrayList<Exception> getExceptionAllPropertiesHavingClassInDomain() {
		return this.exceptionAllPropertiesHavingClassInDomain;
	}

	protected void addExceptionAllPropertiesHavingClassInRange( Exception ex ) {
		
		if( this.exceptionAllPropertiesHavingClassInRange==null )
			this.exceptionAllPropertiesHavingClassInRange = new ArrayList<Exception>();
		this.exceptionOccured = true;
		this.exceptionAllPropertiesHavingClassInRange.add( ex );
	}
	public ArrayList<Exception> getExceptionAllPropertiesHavingClassInRange() {
		return this.exceptionAllPropertiesHavingClassInRange;
	}
	
	/*
	public static ClassContainer select(URI uri, String lang) {

		ClassContainer ret = new ClassContainer();
		
		try {
			
			ret.setLabel( selectLabel(uri, lang) );
			ret.setComment( selectComment(uri, lang) );
			
			ret.setHasVersionDateTime( selectHasVersionDateTime( uri ) );
			ret.setHasPreviousVersion( AbstractDataConnector.selectObject(uri, Vocabulary.HASPREVIOUSVERSION ) );
			
			ret.setSeeAlso( selectSeeAlso(uri) );
			
			ret.setTranslations( selectTranslation( uri ) );
			
			ret.setSynonyms( selectSynonyms(uri) );
			ret.setTags( selectTags(uri) );
			ret.setFlickrImages( selectImages(uri) );
			ret.setYouTubeVideos( selectVideos(uri) );

			ret.setExample( selectExample(uri) );	
			
			ret.setSubClassOf( selectSubclassOf(uri));
			ret.setBelongsToOntologyModule( selectBelongsToOM(uri));
			
			ret.setId(uri);
			
		} catch (Exception e) {
			System.out.println("Error while selecting Class with uri " + uri + ": " + e.getMessage());
		}
		
		return ret;
	}
	*/
	
	
	

	/**
	 * 
	 * @param url	URI of the element which should be updated
	 * @param data contains the values submitted by the user
	 * @param lang language
	 * @return
	 *//*
	public static boolean update(URI uri, model.dataContainer.ClassContainer new_cont, String lang) {
		boolean ret = false;

		try {
			RepositoryConnection con = AbstractDataConnector.getConnection();
			try {
				
				Date timestamp = AbstractMapper.selectHasVersionDateTime(uri);

				updateComment(con, uri, new_cont.getComment(), lang );
				updateExample(con, uri, new_cont.getExample() );
				updateSynonyms(con, uri, new_cont.getSynonyms() );
				updateTags( con, uri, new_cont.getTags() );
				updateImages( con, uri, new_cont.getFlickrImages() );
				updateVideos( con, uri, new_cont.getYouTubeVideos() );
				
				updateTranslations( con, uri, new_cont.getTranslations() );
				
				updateSeeAlso( con, uri, new_cont.getSeeAlso() );
				
				updateBelongsToOM( con, uri, new_cont.getBelongsToOntologyModule() );
				
				updateSubclassOf( con, uri, new_cont.getSubClassOf() );

				
				
				con.commit();
				ret = true;
			} catch( Exception e ) {
				con.rollback();		
				throw e;			
			} finally {
				con.close();
			}
		}catch (Exception e) {
			System.out.println("error during update of class: " + e.getMessage());
		}
		
		return ret;
	}*/
	
	public static ArrayList<URI> selectAll() {
		
		return AbstractDataConnector.selectAllUris( Vocabulary.CLASS );
	}
	
	/*
	public URI copy( URI oldId, String newLabel ) throws Exception {
		
		URI ret = null;
		
		ClassContainer cont = select( oldId, Vocabulary.ENGLISH );		
		cont.setLabel( newLabel );		
		URI newId = this.insert( cont, Vocabulary.ENGLISH );	
		
		if( newId!=null ) {
			
			// copy all tripels, where the oldIdEntry is found in objects (except those, which are defined in the insert-method
			copyTriples( Vocabulary.DOMAIN, oldId, newId );
			copyTriples( Vocabulary.RANGE, oldId, newId );
			copyTriples( Vocabulary.SUBCLASSOF, oldId, newId );
			
			// mark the old ID, that it was renamed:				
			AbstractDataConnector.insertTripel( oldId, Vocabulary.WASRENAMEDTO, newId );
			
			ret = newId;
		}
		
		return ret;		
	}
	*/

	/**
	 * insert an class into the sesame store
	 * @param data an class object
	 * @param lang the language in which the class should be inserted
	 * @return true if the class was inserted
	 *//*
	public URI insert(ClassContainer data, String lang) throws ControllerException {
		URI ret = null;
	
		try {
			RepositoryConnection con = AbstractDataConnector.getConnection();	

			try {
				
				URI id = super.insert(con, data, lang);
				
				//insert all the data of the AbstractElement
				if ( id != null ) {
					
	
					if( data.getExample()!=null )
						con.add(id, Vocabulary.HASEXAMPLE, new LiteralImpl(data.getExample(), lang));

					// addURIs(con, id, Vocabulary.BELONGSTOONTOLOGYMODULE, data.getBelongsToOntologyModule() );
					// archive OntologyModules:
					VersioningMapper.archiveRemoveInsertSubjects(con, null, data.getBelongsToOntologyModule(), id, Vocabulary.BELONGSTOONTOLOGYMODULE );
									
					// not sure if subClass should be archived or this class (subject or object)...
					AbstractDataConnector.addURIs(con, id, Vocabulary.SUBCLASSOF, data.getSubClassOf() );
					// VersionsConnector.archiveRemoveInsertURIs(con, null, data.getSubClassOf(), id, Vocabulary.SUBCLASSOF );	
				
					con.commit();
					
					ret = id;
				}
				else {
					con.rollback();
				}
			} catch( Exception e ) {
				con.rollback();	
				throw e;				
			}
			finally {
				con.close();
			}
		}catch (Exception e) {
			System.out.println("inserting the class failed: " + e.getMessage());
			if (e instanceof ControllerException)
				throw (ControllerException) e;
		}

		
		return ret;
	}*/
	
	

	// ######################################################################################
	// ######################################################################################


	public static ArrayList<URI> selectPartlyOverlapsWith( URI uri ) throws Exception {
		
		return selectPartlyOverlapsWith( uri, Vocabulary.PARTLYOVERLAPSWITHCLASS );
	}
	public boolean updatePartlyOverlapsWith( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		return updatePartlyOverlapsWith(con, uri, Vocabulary.PARTLYOVERLAPSWITHCLASS, newEntry, oldtimestamp);
	}
	

	public static ArrayList<URI> selectSameAs( URI uri ) throws Exception {
		
		return selectSameAs( uri, Vocabulary.SAMECLASSAS );
	}
	public boolean updateSameAs( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		return updateSameAs(con, uri, Vocabulary.SAMECLASSAS, newEntry, oldtimestamp);
	}
	

	public static ArrayList<URI> selectNarrowerThan( URI uri ) throws Exception {
		
		return selectNarrowerThan( uri, Vocabulary.NARROWERTHANCLASSES );
	}
	public boolean updateNarrowerThan( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		return updateNarrowerThan(con, uri, Vocabulary.NARROWERTHANCLASSES, newEntry, oldtimestamp);
	}
	public boolean insertNarrowerThan( RepositoryConnection con, URI uri, ArrayList<URI> newEntry ) throws Exception {

		return insertNarrowerThan(con, uri, Vocabulary.NARROWERTHANCLASSES, newEntry );
	}
	

	public static ArrayList<URI> selectBroaderThan( URI uri ) throws Exception {

		ArrayList<URI> ret = AbstractDataConnector.selectSubjects( Vocabulary.NARROWERTHANCLASSES, VersioningMapper.getMostActualVersion(uri), Vocabulary.CLASS );
		
		return ret;
	}
	public boolean updateBroaderThan( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		boolean ret = false;
		
		try {			
			ArrayList<URI> actualEntry = selectBroaderThan( uri );
			ArrayList<URI> oldEntry = selectBroaderThan( Mapper.selectVersionUri(uri, oldtimestamp) );

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						oldEntry );
				
				VersioningMapper.archiveRemoveInsertObjects(
						con, 
						actualEntry, 
						newEntry, 
						uri, 
						Vocabulary.NARROWERTHANCLASSES );

				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						selectBroaderThan( uri ) );
			}
			ret = true;	
		}
		catch( Exception ex ) {
			this.addExceptionBroaderThan( ex );
		}
		
		return ret;		
	}

	
	public static ArrayList<URI> selectSubclassOf( URI uri ) throws Exception {
		return generateURIObjects( uri, Vocabulary.SUBCLASSOF );
	}	
	/*
	public boolean updateSubclassOf( RepositoryConnection con, URI uri, String entry, String oldtimestamp ) throws Exception {

		boolean ret = false;
		
		try {
	
			ArrayList<URI> actualEntry = selectSubclassOf( uri );
			ArrayList<URI> oldEntry = selectSubclassOf( Mapper.selectVersionUri(uri, oldtimestamp) );
			ArrayList<URI> newEntry = HelperFunctions.extractURIs(entry);

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
					actualEntry,
					oldEntry );
				
				VersioningMapper.archiveRemoveInsertURIs(
						con, 
						actualEntry, 
						newEntry, 
						uri, 
						Vocabulary.SUBCLASSOF );
			}
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionSubclassOf( ex );
		}
		
		return ret;			
	}
	*/
	public boolean updateSubclassOf( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		boolean ret = false;
		
		try {
	
			ArrayList<URI> actualEntry = selectSubclassOf( uri );
			ArrayList<URI> oldEntry = selectSubclassOf( Mapper.selectVersionUri(uri, oldtimestamp) );

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
					actualEntry,
					oldEntry );
				
				VersioningMapper.archiveRemoveInsertURIs(
						con, 
						actualEntry, 
						newEntry, 
						uri, 
						Vocabulary.SUBCLASSOF );
				
				// this will block other threads from overtaking this thread; do not know exectely why but it works...
				Mapper.checkIfStoredInMeantime( 
					actualEntry, 
					selectSubclassOf( uri ) );
			}
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionSubclassOf( ex );
		}
		
		return ret;			
	}
	public boolean insertSubclassOf( RepositoryConnection con, URI uri, ArrayList<URI> entry ) throws Exception {

		boolean ret = false;
		
		try {
			
			AbstractDataConnector.addURIs(con, uri, Vocabulary.SUBCLASSOF, entry );
			
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionSubclassOf( ex );
		}
		
		return ret;
	}
	public boolean insertSubclassOf( RepositoryConnection con, URI uri, String newEntry ) throws Exception {

		boolean ret = false;
		
		try {
			
			ArrayList<URI> entry = HelperFunctions.extractURIs(newEntry);
			
			AbstractDataConnector.addURIs(con, uri, Vocabulary.SUBCLASSOF, entry );
			
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionSubclassOf( ex );
		}
		
		return ret;
	}
	
	
	public static ArrayList<URI> selectBelongsToOM( URI uri ) throws Exception {
		
		return Mapper.selectBelongsToOM(uri);
	}
	public boolean updateBelongsToOM( RepositoryConnection con, URI uri, String entry, String oldtimestamp ) throws Exception {

		return super.updateBelongsToOM(con, uri, entry, oldtimestamp);	
	}
	public boolean updateBelongsToOM( RepositoryConnection con, URI uri, ArrayList<URI> entry, String oldtimestamp ) throws Exception {

		return super.updateBelongsToOM(con, uri, entry, oldtimestamp);	
	}
	/*
	public boolean insertBelongsToOM( RepositoryConnection con, URI uri, ArrayList<URI> entry ) throws Exception {

		return super.insertBelongsToOM(con, uri, entry);
	}
	public boolean insertBelongsToOM( RepositoryConnection con, URI uri, String newEntry ) throws Exception {

		return super.insertBelongsToOM(con, uri, newEntry);
	}
	*/

	/**
	 * returns all classes where the most actual version of the given id is in subclassof 
	 * @return	List of URIs of the classes which are in range
	 * @param clurl 	The URI of the Class for which the superclasses should be found
	 */
	public static ArrayList<URI> selectAllClassesHavingClassInSubClassOf( URI id ) throws Exception {

		ArrayList<URI> ret = AbstractDataConnector.selectSubjects(Vocabulary.SUBCLASSOF, VersioningMapper.getMostActualVersion(id), Vocabulary.CLASS);
		
		return ret;
	}
	public boolean updateAllClassesHavingClassInSubClassOf( RepositoryConnection con, URI uri, String entry, String oldentry ) throws Exception {

		boolean ret = false;
		
		entry = trimEntry(entry);		
		
		try {
			
			ArrayList<URI> actualEntry = selectAllClassesHavingClassInSubClassOf( uri );
			// ArrayList<URI> oldEntry = selectAllClassesHavingClassInSubClassOf( Mapper.selectVersionUri(uri, oldtimestamp) );
			// actualEntry and oldEntry will always be the same as never c1 subclassOf c2/v0 would exist. superclass are archived with c1 and not with c2!
			ArrayList<URI> oldEntry = HelperFunctions.extractURIs(oldentry);			
			ArrayList<URI> newEntry = HelperFunctions.extractURIs(entry);

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						oldEntry );
				
				VersioningMapper.archiveRemoveInsertObjects(
						con, 
						actualEntry, 
						newEntry, 
						uri, 
						Vocabulary.SUBCLASSOF );
				
				// this will block other threads from overtaking this thread; do not know exectely why but it works...
				Mapper.checkIfStoredInMeantime( 
					actualEntry, 
					selectAllClassesHavingClassInSubClassOf( uri ) );
			}
			ret = true;	
		}
		catch( Exception ex ) {
			this.addExceptionAllClassesHavingClassInSubClassOf( ex );
		}
		
		return ret;		
	}
	public boolean updateAllClassesHavingClassInSubClassOf( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		boolean ret = false;
		
		try {			
			ArrayList<URI> actualEntry = selectAllClassesHavingClassInSubClassOf( uri );
			ArrayList<URI> oldEntry = selectAllClassesHavingClassInSubClassOf( Mapper.selectVersionUri(uri, oldtimestamp) );

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						oldEntry );
				
				VersioningMapper.archiveRemoveInsertObjects(
						con, 
						actualEntry, 
						newEntry, 
						uri, 
						Vocabulary.SUBCLASSOF );
				
				// this will block other threads from overtaking this thread; do not know exectely why but it works...
				Mapper.checkIfStoredInMeantime( 
					actualEntry, 
					selectAllClassesHavingClassInSubClassOf( uri ) );
			}
			ret = true;	
		}
		catch( Exception ex ) {
			this.addExceptionAllClassesHavingClassInSubClassOf( ex );
		}
		
		return ret;		
	}
	

	/**
	 * returns all properties where the given id is in domain 
	 * @return	List of URIs of the classes which are in domain
	 * @param clurl 	The URI of the Class for which the properties should be found (which have class in domain)
	 */
	public static ArrayList<URI> selectAllPropertiesHavingClassInDomain( URI id ) throws Exception {
		// return ClassConnector.selectAllPropertiesHavingClassInDomain( id );
				
		ArrayList<URI> ret = generateSubjectsOfArchiveableObject( Vocabulary.DOMAIN, id );
		
		/*
		// filter by type:
		if( tmp!=null ) {
			Iterator<URI> iter = tmp.iterator();
			while( iter.hasNext() ) {
				URI next = iter.next();
				URI type = AbstractDataConnector.getType( next );
				if( type.equals(Vocabulary.CLASS) ){
					
					if( ret==null ){
						ret = new ArrayList<URI>();
					}
					
					ret.add(next);
				}
			}
		}
		*/
		
		return ret;
	}
	
	/**
	 * returns all properties where the given id is in domain 
	 * @return	List of URIs of the classes which are in domain
	 * @param clurl 	The URI of the Class for which the properties should be found (which have class in domain)
	 */
	public static ArrayList<URI> selectAllInstancesHavingClassInDomain( URI id ) throws Exception {
		// return ClassConnector.selectAllPropertiesHavingClassInDomain( id );
				
		ArrayList<URI> ret = generateSubjectsOfArchiveableObject( Vocabulary.ISINSTANCEOF, id );
		
		/*
		// filter by type:
		if( tmp!=null ) {
			Iterator<URI> iter = tmp.iterator();
			while( iter.hasNext() ) {
				URI next = iter.next();
				URI type = AbstractDataConnector.getType( next );
				if( type.equals(Vocabulary.CLASS) ){
					
					if( ret==null ){
						ret = new ArrayList<URI>();
					}
					
					ret.add(next);
				}
			}
		}
		*/
		
		return ret;
	}
	public boolean updateAllPropertiesHavingClassInDomain( RepositoryConnection con, URI uri, String entry, String oldtimestamp ) throws Exception {

		boolean ret = false;
		
		entry = trimEntry(entry);	
		
		try {
	
			ArrayList<URI> actualEntry = selectAllPropertiesHavingClassInDomain( uri );
			ArrayList<URI> oldEntry = selectAllPropertiesHavingClassInDomain( Mapper.selectVersionUri(uri, oldtimestamp) );
			ArrayList<URI> newEntry = HelperFunctions.extractURIs(entry);

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						oldEntry );
				
				VersioningMapper.archiveRemoveInsertSubject(
						con, 
						actualEntry, 
						newEntry, 
						uri, 
						Vocabulary.DOMAIN );
			}
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionAllPropertiesHavingClassInDomain( ex );
		}
		
		return ret;			
	}
	public boolean updateAllPropertiesHavingClassInDomain( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		boolean ret = false;
		
		try {
	
			ArrayList<URI> actualEntry = selectAllPropertiesHavingClassInDomain( uri );
			ArrayList<URI> oldEntry = selectAllPropertiesHavingClassInDomain( Mapper.selectVersionUri(uri, oldtimestamp) );

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						oldEntry );
				
				VersioningMapper.archiveRemoveInsertSubject(
						con, 
						actualEntry, 
						newEntry, 
						uri, 
						Vocabulary.DOMAIN );
				
				// this will block other threads from overtaking this thread; do not know exectely why but it works...
				Mapper.checkIfStoredInMeantime( 
					actualEntry, 
					selectAllPropertiesHavingClassInDomain( uri ) );
			}
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionAllPropertiesHavingClassInDomain( ex );
		}
		
		return ret;			
	}
	public boolean insertAllPropertiesHavingClassInDomain( RepositoryConnection con, URI uri, ArrayList<URI> newEntry ) throws Exception {

		boolean ret = false;
		
		try {

			if( newEntry!=null ) {
				Iterator<URI> iter = newEntry.iterator();
				while( iter.hasNext() ) {

					URI subj = iter.next();
				
					con.add( 
							subj, 
							Vocabulary.DOMAIN, 
							uri );
				}
			}
				
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionAllPropertiesHavingClassInDomain( ex );
		}
		
		return ret;			
	}
	public boolean insertAllPropertiesHavingClassInDomain( RepositoryConnection con, URI uri, String entry ) throws Exception {

		boolean ret = false;
		
		try {
			ArrayList<URI> newEntry = HelperFunctions.extractURIs(entry);
			
			if( newEntry!=null ) {
				Iterator<URI> iter = newEntry.iterator();
				while( iter.hasNext() ) {

					URI subj = iter.next();
				
					con.add( 
							subj, 
							Vocabulary.DOMAIN, 
							uri );
				}
			}
			
			ret = true;
	
		}catch (Exception ex) {
			this.addExceptionAllPropertiesHavingClassInDomain( ex );
		}	
		
		/*try {
			ArrayList<URI> newEntry = HelperFunctions.extractURIs(entry);

			VersioningMapper.archiveRemoveInsertSubject(
					con, 
					null, 
					newEntry, 
					uri, 
					Vocabulary.DOMAIN );
				
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionAllPropertiesHavingClassInDomain( ex );
		}
		*/
		
		return ret;	

	}
	

	/**
	 * returns all properties where the given id is in range 
	 * @return	List of URIs of the classes which are in range
	 * @param clurl 	The URI of the Class for which the properties should be found (which have class in range)
	 */
	public static ArrayList<URI> selectAllPropertiesHavingClassInRange( URI id ) throws Exception {
		// return ClassConnector.selectAllPropertiesHavingClassInDomain( id );
		
		ArrayList<URI> ret = AbstractDataConnector.selectSubjects( Vocabulary.RANGE, VersioningMapper.getMostActualVersion(id), Vocabulary.OBJECTPROPERTY ); // DatatypeProperties cannot have a class in Range!
				
		return ret;
	}
	public boolean updateAllPropertiesHavingClassInRange( RepositoryConnection con, URI uri, ArrayList<URI> newEntry, String oldtimestamp ) throws Exception {

		boolean ret = false;
		
		try {			

			ArrayList<URI> actualEntry = selectAllPropertiesHavingClassInRange( uri );
			ArrayList<URI> oldEntry = selectAllPropertiesHavingClassInRange( Mapper.selectVersionUri(uri, oldtimestamp) );
			

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						oldEntry );
				
				VersioningMapper.archiveRemoveInsertObjects( 
						con, 
						selectAllPropertiesHavingClassInRange( uri ), 
						newEntry, 
						uri, 
						Vocabulary.RANGE );
			}
			
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionAllPropertiesHavingClassInRange( ex );
		}
		
		return ret;					
	}
	public boolean updateAllPropertiesHavingClassInRange( RepositoryConnection con, URI uri, String entry, String oldentry ) throws Exception {

		boolean ret = false;
		
		entry = trimEntry(entry);		
		
		try {			

			ArrayList<URI> actualEntry = selectAllPropertiesHavingClassInRange( uri );	
			// ArrayList<URI> oldEntry = selectAllPropertiesHavingClassInRange( Mapper.selectVersionUri(uri, oldtimestamp) );
			// actualEntry and oldEntry will always be the same as never p range c/v0 would exist. Ranges are archived with p and not with c!
			ArrayList<URI> oldEntry = HelperFunctions.extractURIs(oldentry);
			ArrayList<URI> newEntry = HelperFunctions.extractURIs(entry);
			

			if( isOneEntryDifferent( actualEntry, newEntry ) ) {
				Mapper.checkIfStoredInMeantime( 
						actualEntry,
						oldEntry );
				
				VersioningMapper.archiveRemoveInsertObjects( 
						con, 
						selectAllPropertiesHavingClassInRange( uri ), 
						newEntry, 
						uri, 
						Vocabulary.RANGE );
				
				// this will block other threads from overtaking this thread; do not know exectely why but it works...
				Mapper.checkIfStoredInMeantime( 
					actualEntry, 
					selectAllPropertiesHavingClassInRange( uri ) );
			}
			
			ret = true;
		}
		catch( Exception ex ) {
			this.addExceptionAllPropertiesHavingClassInRange( ex );
		}
		
		return ret;					
	}
	
	
	
	

}
